<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增删改查</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <link rel="stylesheet" href="style.css">
    <style>

    </style>
</head>
<body>
<div id="app">
    <div class="container">
        <div class="form-group">
            <label>Search</label>
            <input type="text" class="search-input" v-model="searchQuery" />
        </div>

    </div>
    <div class="container">
        <simple-grid :data-list="people" :columns="columns" :search-key="searchQuery">
        </simple-grid>
    </div>
</div>

<template id="grid-template">
    <table>
        <thead>
        <tr>
            <th v-for="col in columns">
                {{ col.name | capitalize}}
            </th>
            <th>
                Delete
            </th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="(index,entry) in dataList | filterBy searchKey">
            <td v-for="col in columns">
                <span v-if="col.isKey"><a href="javascript:void(0)" @click="openEditItemDialog(entry[col.name])">{{entry[col.name]}}</a></span>
                <span v-else>{{entry[col.name]}}</span>
            </td>
            <td class="text-center">
                <button class="btn-danger" @click="deleteItem(entry)">delete</button>
            </td>
        </tr>
        </tbody>
    </table>
    <div class="container">
        <button class="btn" @click="openNewItemDialog('Create New Item')">Create</button>
    </div>

    <modal-dialog :mode="mode" :title="title" :item="item" :fields="columns" v-on:create-item="createItem" v-on:update-item="updateItem">
    </modal-dialog>

</template>

<template id="dialog-template">
    <div class="dialogs">
        <div class="dialog" v-bind:class="{ 'dialog-active': show }">
            <div class="dialog-content">

                <header class="dialog-header">
                    <h1 class="dialog-title">{{ title }}</h1>
                </header>
                <div class="dialog-body">
                    <div v-for="field in fields" class="form-group">
                        <label>{{ field.name }}</label>
                        <select v-if="field.dataSource" v-model="item[field.name]" :disabled="mode === 2 && field.isKey">
                            <option v-for="opt in field.dataSource" :value="opt">{{ opt }}</option>
                        </select>
                        <input v-else type="text" v-model="item[field.name]" :disabled="mode === 2 && field.isKey">
                    </div>
                </div>
                <footer class="dialog-footer">
                    <div class="form-group">
                        <label></label>
                        <button class="btn-save" v-on:click="save">Save</button>
                        <button class="btn-close" v-on:click="close">Close</button>
                    </div>
                </footer>
            </div>
        </div>
        <div class="dialog-overlay"></div>
    </div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    Vue.component('simple-grid', {
        template: '#grid-template',
        props: ['dataList', 'columns', 'searchKey'],
        data: function() {
            return {
                mode: 0,
                title: '',
                keyColumn: '',
                item: {}
            }
        },
        ready: function() {
            for(var i = 0; i < this.columns.length; i++) {
                if(this.columns[i].isKey) {
                    this.keyColumn = this.columns[i]['name']
                    break;
                }
            }
        },
        methods: {
            openNewItemDialog: function(title) {
                // 对话框的标题
                this.title = title
                // mode = 1表示新建模式
                this.mode = 1
                // 初始化this.item
                this.item = {}
                // 广播事件，showDialog是modal-dialog组件的一个方法，传入参数true表示显示对话框
                this.$broadcast('showDialog', true)
            },
            openEditItemDialog: function(key) {
                // 根据主键查找当前修改的数据
                var currentItem = this.findItemByKey(key)
                // 对话框的标题
                this.title = 'Edit Item - ' + key
                // mode = 2表示修改模式
                this.mode = 2
                // 将选中的数据拷贝到this.item
                this.item = this.initItemForUpdate(currentItem)
                // 广播事件，传入参数true表示显示对话框
                this.$broadcast('showDialog', true)
            },
            // 弹出修改数据的对话框时，使用对象的深拷贝
            initItemForUpdate(p, c) {
                c = c || {};
                for(var i in p) {
                    // 属性i是否为p对象的自有属性
                    if(p.hasOwnProperty(i)) {
                        // 属性i是否为复杂类型
                        if(typeof p[i] === 'object') {
                            // 如果p[i]是数组，则创建一个新数组
                            // 如果p[i]是普通对象，则创建一个新对象
                            c[i] = Array.isArray(p[i]) ? [] : {};
                            // 递归拷贝复杂类型的属性
                            this.initItemForUpdate(p[i], c[i]);
                        } else {
                            // 属性是基础类型时，直接拷贝
                            c[i] = p[i];
                        }
                    }
                }
                return c;
            },
            findItemByKey: function(key) {
                var keyColumn = this.keyColumn
                for(var i = 0; i < this.dataList.length; i++) {
                    if(this.dataList[i][keyColumn] === key) {
                        return this.dataList[i]
                    }
                }
            },
            itemExists: function() {
                var keyColumn = this.keyColumn
                for(var i = 0; i < this.dataList.length; i++) {
                    if(this.item[keyColumn] === this.dataList[i][keyColumn])
                        return true;
                }
                return false;
            },
            createItem: function() {
                var keyColumn = this.keyColumn
                if(!this.itemExists()) {
                    // 将item追加到dataList
                    this.dataList.push(this.item)
                    // 广播事件，传入参数false表示隐藏对话框
                    this.$broadcast('showDialog', false)
                    // 新建完数据后，重置item对象
                    this.item = {}
                } else {
                    alert(keyColumn + ' "' + this.item[keyColumn] + '" is already exists')
                }

            },
            updateItem: function() {

                // 获取主键列
                var keyColumn = this.keyColumn

                for(var i = 0; i < this.dataList.length; i++) {
                    // 根据主键查找要修改的数据，然后将this.item数据更新到this.dataList[i]
                    if(this.dataList[i][keyColumn] === this.item[keyColumn]) {
                        for(var j in this.item) {
                            this.dataList[i][j] = this.item[j]
                        }
                        break;
                    }
                }
                // 广播事件，传入参数false表示隐藏对话框
                this.$broadcast('showDialog', false)
                // 修改完数据后，重置item对象
                this.item = {}
            },
            deleteItem: function(entry) {
                var data = this.dataList
                data.forEach(function(item, i) {
                    if(item === entry) {
                        data.splice(i, 1)
                        return
                    }
                })
            }
        },
        components: {
            'modal-dialog': {
                template: '#dialog-template',
                data: function() {
                    return {
                        // 对话框默认是不显示的
                        show: false
                    }
                },
                /*
                 * mode = 1是新增数据模式，mode = 2是修改数据模式
                 * title表示对话框的标题内容
                 * fields表示对话框要显示的数据字段数组
                 * item是由simple-dialog传下来，用于绑定表单字段的
                 */
                props: ['mode', 'title', 'fields', 'item'],
                methods: {
                    close: function() {
                        this.show = false
                    },
                    save: function() {
                        if(this.mode === 1) {
                            // 使用$dispatch调用simple-grid的create-item事件
                            this.$dispatch('create-item')
                        } else if(this.mode === 2) {
                            // 使用$dispatch调用simple-grid的update-item事件
                            this.$dispatch('update-item')
                        }
                    }
                },
                events: {
                    'showDialog': function(show) {
                        this.show = show
                    }
                }
            }
        }
    })

    var demo = new Vue({
        el: '#app',
        data: {
            searchQuery: '',
            columns: [{
                name: 'name',
                isKey: true
            }, {
                name: 'age'
            }, {
                name: 'sex',
                dataSource: ['Male', 'Female']
            }],
            people: [{
                name: 'Jack',
                age: 30,
                sex: 'Male'
            }, {
                name: 'Bill',
                age: 26,
                sex: 'Male'
            }, {
                name: 'Tracy',
                age: 22,
                sex: 'Female'
            }, {
                name: 'Chris',
                age: 36,
                sex: 'Male'
            }]
        }
    })
</script>

</body>
</html>
